`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: University of Utah
// Engineer: David Hurst, Tyson Hunt, Chase Hochstrasser
// 
// Create Date:    15:54:42 08/30/2011 
// Design Name: 
// Module Name:    ALUUnit 
// Project Name:  ALU Design
// Target Devices: 
// Tool versions: 
// Description: Make Calculations according to the opcodes called by test or user.
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: ALU operations / Calculations
//
//////////////////////////// //////////////////////////////////////////////////////
module ALUUnit(A, B, op, result, F, Cin);

   input [15:0] A,B;
   input [7:0] op;
	input Cin;
  
   output [15:0] result;
   output [4:0] F;
	 
	reg [15:0] result;
	reg [4:0] F;

//FLAGS , EZCONL Zero, carry, overflow, negative, low,
/*
Opcodes

		s2	s1 s0
CMP	0	0  0 2'sc
ADD   0	0  1
SUB   0  1  0 2'sc
ADDU  0  1  1

*/

`include "opcode.v"


 
always @(A,B,op,Cin) begin

 
case(op)
 
 ADDU: begin 
   
		{F[carry], result} = A+B;
		if(result == 0)
			F[zero] = 1;
		else 
			F[zero] = 0;
		
		F[2:0] = 3'b000;
		end
 
 
 ADDUI: begin

		{F[carry], result} = A + ($signed(B[7:0]));
		if(result == 0)
			F[zero] = 1;
		else 
			F[zero] = 0;
		
		F[2:0] = 3'b000;
		end
		
		
 ADD: begin
 
		result = A+B;
		F[carry] = 0;
		if(result == 0)
			F[zero] = 1;
		else 
			F[zero] = 0;
		//Overflow
		F[2] = (~A[15]&~B[15] & result[15]) | (A[15]&B[15]&~result[15]);
	
		F[1:0] = 2'b00;
		end
		
 ADDI: begin
 
		result = A+($signed(B[7:0]));
		F[carry] = 0;
		if(result == 4'b0000)
			F[zero] = 1;
		else
			F[zero] = 0;
		//Overflow
		F[2] = (~A[15]&~B[15] & result[15]) | (A[15]&B[15]&~result[15]);
	
		F[1:0] = 2'b00;
		end
		
		
 ADDC: begin
 
		result = A+B+Cin;
		F[carry] = 0;
		if(result == 0)
			F[zero] = 1;
		else
			F[zero] = 0;
		//Overflow
		F[2] = (~A[15]&~B[15] & result[15]) | (A[15]&B[15]&~result[15]);
		F[1:0] = 2'b00;
		
		end
 
 ADDCI: begin
 
		result = A+($signed(B[7:0]))+Cin;
		F[carry] = 0;
		if(result == 0)
			F[zero] = 1;
		else 
			F[zero] = 0;
		//Overflow
		F[2] = (~A[15]&~B[15] & result[15]) | (A[15]&B[15]&~result[15]);
		F[1:0] = 2'b00;

 end
	
 SUB: begin //2'sc only
		
		result=A-B;//F = A+ (2'cB)
		if(result == 0) F[zero] = 1;
		else F[zero] = 0;
		F[3] = 1'b0;
		F[1:0] = 2'b00;
		//overflow
		F[2] = (A[15]&~B[15] & ~result[15]) | (~A[15]&B[15] & result[15]);
		
		end
 
 SUBI: begin
 
		result=A - {{8{B[7]}},{B[7:0]}};
		if(result == 0) F[zero] = 1;
		else F[zero] = 0;
		F[3] = 1'b0;
		F[1:0] = 2'b00;
		//overflow
		F[2] = (A[15]&~B[15] & ~result[15]) | (~A[15]&B[15]& result[15]);
		 
		end
 
 CMP: begin //A<B
 
 if($signed(A) < $signed(B))
	F[1:0] = 2'b11;
 else F[1:0]= 2'b00;
   
 if(A==B)
	F[zero] = 1'b1;
 else		
	F[zero] = 0;
  
		
 F[3:2] = 3'b000;
 result = 16'bxxxxxxxxxxxxxxxx;
			
end

 CMPI: begin //A<B
 
 if($signed(A) < $signed(B[7:0]))
	F[1:0] = 2'b11;
 else F[1:0]= 2'b00;
   
 if(A==B)
	F[zero] = 1'b1;
 else		
	F[zero] = 0;
  
		
 F[3:2] = 3'b000;
 result = 16'bxxxxxxxxxxxxxxxx;
			
end


OR: begin

	result = A|B;
	F[4:0] = 5'b00000;
	
	end
	
ORI: begin

   result = A|B;
	F[4:0] = 5'b00000;
	
end

AND: begin

	result = A&B;
	F[4:0] = 5'b00000;
	
	end
	
ANDI: begin

	result = A & {{8{1'b0}},{B[7:0]}};
	F[4:0] = 5'b00000;

   end

XOR: begin

	result = A^B;
	F[4:0] = 5'b00000;
	
	end
	
XORI: begin

	result = A ^ {{8{1'b0}},{B[7:0]}};
	F[4:0] = 5'b00000;

   end

MOV: begin

	result = B;
	F[4:0] = 5'b00000;
	
	end
	
MOVI: begin

	result = {{8{1'b0}},{B[7:0]}};
	F[4:0] = 5'b00000;

	end

LOAD: begin

	result = A;
	F[4:0] = 5'b00000;
	
	end
	
STOR: begin

	result = A;
	F[4:0] = 5'b00000;
	
	end

ASHU: begin

	if ($signed(B[15:0]) >= 0)
		result = $signed(A) >>> B[3:0];
	else 
		result = A <<< {{12{1'b0}},{~B[3:0]}} + 1;
	
	F[4:0] = 5'b00000;
end

ASHUI: begin

	if ($signed(B[4:0]) >= 0)
		result = $signed(A) >>> B[4:0];
	else 
		result = A <<< {{11{1'b0}},{~B[4:0]}} + 1;
	
	F[4:0] = 5'b00000;
end

LSHI: begin

if ($signed(B[4:0]) >= 0)
		result = A >> B[4:0];
	else 
		result = A << {{11{1'b0}},{~B[4:0]}} + 1;
	
	F[4:0] = 5'b00000;
end

LSH: begin

	if ($signed(B[15:0]) >= 0)
		result = A >> B[3:0];
	else 
		result = A << {{12{1'b0}},{~B[3:0]}} + 1;
	
	F[4:0] = 5'b00000;

end

Jcond: begin
  result = B;
  F[4:0] = 5'b00000;
end

default: begin
  result = 16'bxxxxxxxxxxxxxxxx;
  F[4:0] = 5'bxxxxx;
 end
  
endcase
 
end

endmodule
